import { useEffect, useState, useRef } from "react";
import styles from './index.less';
import type { RadioChangeEvent, CollapseProps } from 'antd';
import { Button, Radio, message, Collapse } from 'antd';
import PF from 'pathfinding';
import AStarFinder from "./components/AStarFinder";
import BreadthFirstFinder from "./components/BreadthFirstFinder";
import IDAStarFinder from "./components/IDAStarFinder";

const CELL_SIZE = 30;

// 0：正常可通过，1：障碍不可通过，-1：起点，-2：终点
type CellType = 0 | 1 | -1 | -2;

type Cell = {
    x: number;
    y: number;
    type: CellType;
};

type Action = 'Start' | 'End' | 'Wall' | 'Clear';

type Algorithm = 'AStarFinder' 
    | 'BestFirstFinder' 
    | 'BreadthFirstFinder' 
    | 'DijkstraFinder' 
    | 'IDAStarFinder' 
    | 'OrthogonalJumpPointFinder' 
    | 'BiAStarFinder' 
    | 'BiBestFirstFinder' 
    | 'BiBreadthFirstFinder' 
    | 'BiDijkstraFinder';

export default () => {
    const mapViewRef = useRef<HTMLDivElement>(null);

    const [xCount, setXCount] = useState<number>(0);
    const [yCount, setYCount] = useState<number>(0);

    const [isLeftPressed, setIsLeftPressed] = useState(false);

    const [action, setAction] = useState<Action>('Start');

    const [cells, setCells] = useState<Cell[]>([]);

    const [currentCell, setCurrentCell] = useState<Cell | null>(null);

    const cacheCells = useRef<Cell[]>([]);

    const [algorithm, setAlgorithm] = useState<Algorithm>('AStarFinder');

    const [config, setConfig] = useState<any>({
        allowDiagonal: true,
        dontCrossCorners: false,
        weight: 0,
        diagonalMovement: 1,
    });

    const [path, setPath] = useState<number[][]>([]);

    useEffect(() => {
        const mapWidth = mapViewRef.current?.clientWidth || 0;
        const mapHeight = mapViewRef.current?.clientHeight || 0;
        const xC = Math.floor(mapWidth / CELL_SIZE);
        const yC = Math.floor(mapHeight / CELL_SIZE);
        setXCount(xC);
        setYCount(yC);

        const cs: Cell[] = [];
        // 这里一定要先循环j，再循环i
        for (let j = 0; j < yC; j++) {
            for (let i = 0; i < xC; i++) {
                cs.push({x: i, y: j, type: 0});
            }
        }

        setCells(cs);
        setPath([]);
    }, []);

    const getColorByType = (item: Cell): string => {
        if (item.type == -1) {
            return '#5DDA44';
        } else if (item.type == -2) {
            return 'red';
        } else {
            if (item.type == 1) {
                return '#AAA';
            } else {
                // 看是不是在已搜索的路径中
                const find =  path.find(i => i[0] == item.x && i[1] == item.y);
                if (find) {
                    return 'orange';
                }
            }
            return 'transparent';
        }
    }
    
    const parseCellsToMatrix = (cells: Cell[]): number[][] => {
        if (!cells?.length) {
            return [];
        }
    
        const groupByY: Record<number, Cell[]> = {};
    
        // 按 y 分组
        cells.forEach((item) => {
            if (!groupByY[item.y]) {
                groupByY[item.y] = [];
            }
            groupByY[item.y].push(item);
        });
    
        // 对每组按 x 排序
        Object.values(groupByY).forEach((group) => {
            group.sort((a, b) => a.x - b.x);
        });
    
        // 提取每组的 type 值
        return Object.values(groupByY).map((group) =>
            group.map((item) => item.type == 1 ? 1 : 0)
        );
    };

    const resetMap = () => {
        const copy = [...cells];
        for (let i = 0; i < copy.length; i++) {
            const item = copy[i];
            item.type = 0;
        }
        setCells(copy);
        setPath([]);
    }

    const buildFinder = (): any => {
        console.log(`## config=${JSON.stringify(config)}`);
        if (algorithm == 'AStarFinder') {
            return new PF.AStarFinder({ allowDiagonal: config.allowDiagonal, dontCrossCorners: config.dontCrossCorners, weight: config.weight, diagonalMovement: parseInt(config.diagonalMovement) });
        } else if (algorithm == 'BestFirstFinder') {
            return new PF.BestFirstFinder();
        } else if (algorithm == 'BreadthFirstFinder') {
            return new PF.BreadthFirstFinder({ diagonalMovement: parseInt(config.diagonalMovement) });
        } else if (algorithm == 'DijkstraFinder') {
            return new PF.DijkstraFinder();
        } else if (algorithm == 'IDAStarFinder') {
            return new PF.IDAStarFinder();
        } else if (algorithm == 'BiAStarFinder') {
            return new PF.BiAStarFinder({ diagonalMovement: parseInt(config.diagonalMovement) });
        } else if (algorithm == 'BiBestFirstFinder') {
            return new PF.BiBestFirstFinder({ diagonalMovement: parseInt(config.diagonalMovement) });
        } else if (algorithm == 'BiBreadthFirstFinder') {
            return new PF.BiBreadthFirstFinder({ diagonalMovement: parseInt(config.diagonalMovement) });
        } else if (algorithm == 'BiDijkstraFinder') {
            return new PF.BiDijkstraFinder();
        }
        return null;
    }

    const startFinding = () => {
        const start = cells.find(i => i.type == -1);
        const end = cells.find(i => i.type == -2);
        if (!start) {
            message.error('请设置起点');
            return;
        }
        if (!end) {
            message.error('请设置终点');
            return;
        }

        const matrix: number[][] = parseCellsToMatrix(cells);
        const grid = new PF.Grid(matrix);
        const finder = buildFinder();
        if (!finder) {
            message.error('算法不存在');
            return;
        }
        const path = finder.findPath(start.x, start.y, end.x, end.y, grid);
        if (path?.length) {
            setPath(path );
        } else {
            message.error('终点不可到达');
        }
    }

    const handleLeftDown = (e: any) => {
        if (action == 'Start' || action == 'End') {
            const rect = mapViewRef.current?.getBoundingClientRect();
            const x = e.clientX - (rect?.left || 0);
            const y = e.clientY - (rect?.top || 0);
            const xIndex = Math.trunc(x / CELL_SIZE);
            const yIndex = Math.trunc(y / CELL_SIZE);
            const realIndex = yIndex * xCount + xIndex;
            const copy = [...cells];

            if (action == 'Start') {
                const currentStartIndex = copy.findIndex(i => i.type == -1);
                if (currentStartIndex >= 0) {
                    copy[currentStartIndex].type = 0;
                }
                copy[realIndex].type = -1;
            } else {
                const currentStartIndex = copy.findIndex(i => i.type == -2);
                if (currentStartIndex >= 0) {
                    copy[currentStartIndex].type = 0;
                }
                copy[realIndex].type = -2;
            }
            setCells(copy);
            return;
        }
        setIsLeftPressed(true);
    }
    
    const handleMouseMove = (e: any) => {
        if (isLeftPressed) {
            const rect = mapViewRef.current?.getBoundingClientRect();
            const x = e.clientX - (rect?.left || 0);
            const y = e.clientY - (rect?.top || 0);
            const xIndex = Math.trunc(x / CELL_SIZE);
            const yIndex = Math.trunc(y / CELL_SIZE);
            
            // 如果currentCell空，或者和当前鼠标位置不一致，则更新
            if (!currentCell || (currentCell.x != xIndex || currentCell.y != yIndex)) {
                const c: Cell = { x: xIndex, y: yIndex, type: action == 'Wall' ? 1 : 0 };
                setCurrentCell(c);

                // 缓存住这一批
                cacheCells.current?.push(c);
            }
        }
    }

    const handleMouseUp = () => {
        if (action == 'Start' || action == 'End') {
            return;
        }
        setIsLeftPressed(false);
        if (cacheCells.current?.length) {
            const copy = [...cells];
            for (let i = 0; i < cacheCells.current?.length; i++) {
                const item = cacheCells.current[i];
                const realIndex = item.y * xCount + item.x;

                if (copy[realIndex].type != -1 && copy[realIndex].type != -2) {
                    copy[realIndex].type = item.type;
                }
            }
            setCells(copy);
            cacheCells.current = [];
        }
    }

    const text = `暂未支持`;

    const items: CollapseProps['items'] = [
        {
            key: 'AStarFinder',
            label: 'AStarFinder*',
            children: (
                <AStarFinder onConfig={(config: any) => {
                    setConfig(config);
                }}/>
            ),
        },
        {
            key: 'BestFirstFinder',
            label: 'BestFirstFinder',
            children: (
                <BreadthFirstFinder onConfig={(config: any) => {
                    setConfig(config);
                }}/>
            ),
        },
        {
            key: 'BreadthFirstFinder',
            label: 'BreadthFirstFinder*',
            children: (
                <BreadthFirstFinder onConfig={(config: any) => {
                    setConfig(config);
                }}/>
            ),
        },
        {
            key: 'DijkstraFinder',
            label: 'DijkstraFinder*',
            children: (
                <BreadthFirstFinder onConfig={(config: any) => {
                    setConfig(config);
                }}/>
            ),
        },
        {
            key: 'IDAStarFinder',
            label: 'IDAStarFinder*',
            children: (
                <IDAStarFinder onConfig={(config: any) => {
                    setConfig(config);
                }}/>
            ),
        },
        {
            key: 'OrthogonalJumpPointFinder',
            label: 'OrthogonalJumpPointFinder*',
            children: <p>{text}</p>,
        },
        {
            key: 'BiAStarFinder',
            label: 'BiAStarFinder',
            children: (
                <BreadthFirstFinder onConfig={(config: any) => {
                    setConfig(config);
                }}/>
            ),
        },
        {
            key: 'BiBestFirstFinder',
            label: 'BiBestFirstFinder',
            children: (
                <BreadthFirstFinder onConfig={(config: any) => {
                    setConfig(config);
                }}/>
            ),
        },
        {
            key: 'BiBreadthFirstFinder',
            label: 'BiBreadthFirstFinder*',
            children: (
                <BreadthFirstFinder onConfig={(config: any) => {
                    setConfig(config);
                }}/>
            ),
        },
        {
            key: 'BiDijkstraFinder',
            label: 'BiDijkstraFinder*',
            children: <p>无配置项</p>,
        },
    ];

    return (
        <div className={styles.container}>
            <div className={styles.configLayout}>
                <Radio.Group
                    style={{ marginBottom: 10 }}
                    block
                    onChange={(e: RadioChangeEvent) => {
                        setAction(e.target.value as Action);
                    }}
                    value={action}
                    options={[
                        { value: "Start", label: "起点" },
                        { value: "End", label: "终点" },
                        { value: "Wall", label: "障碍" },
                        { value: "Clear", label: "清除" },
                    ]}
                    optionType="button"
                    buttonStyle="solid"
                />

                <Collapse
                    style={{ backgroundColor: '#f0f0f0' }}
                    accordion
                    items={items}
                    activeKey={algorithm}
                    onChange={(key: string[]) => {
                        // @ts-ignore
                        setAlgorithm(key);
                    }}
                />

                <Button type="primary" onClick={startFinding}>开始寻路</Button>

                <Button color="default" variant="solid" onClick={resetMap}>重置地图</Button>
            </div>

            <div
                ref={mapViewRef}
                className={styles.mapLayout}
                onMouseDown={handleLeftDown}
                onMouseMove={handleMouseMove}
                onMouseUp={handleMouseUp}
            >
                {cells?.map((item, index) => {
                    return (
                        <div
                            key={`${item.x}-${item.y}-${index}`}
                            className={styles.cell}
                            style={{backgroundColor: getColorByType(item)}}
                        />
                    );
                })}
            </div>
        </div>
    );
}
